package mylogger

import (
	"fmt"
	"os"
	"path"
	"time"
)

// 这是王文件里面写日志的代码

// FileLogger 文件日志结构体
type FileLogger struct {
	Level    Level
	fileName string
	filePath string
	file     *os.File
	errFile  *os.File
	maxSize  int64
}

// 将指定的日志文件打开 赋值给结构体
func (f *FileLogger) initFile() {
	logName := path.Join(f.filePath, f.fileName)
	// 打开文件
	fileObj, err := os.OpenFile(logName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("打开日志文件 %s失败，err:%v", logName, err))
	}
	f.file = fileObj

	// 打开错误的日志文件
	errLogName := fmt.Sprintf("%s.err", logName)
	errFileObj, err := os.OpenFile(errLogName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("打开日志文件 %s失败，err:%v", logName, err))
	}
	f.errFile = errFileObj
}

// NewFileLogger 定义一个日志文件结构体的构造函数
func NewFileLogger(filePath, fileName, levelStr string) *FileLogger {
	logLevel := paeseLogLevel(levelStr)
	fl := &FileLogger{
		Level:    logLevel,
		fileName: fileName,
		filePath: filePath,
		maxSize:  10 * 1024 * 1024,
	}
	fl.initFile() // 根据上面的文件路径和文件名打开的日志文件，把文件句柄赋值给结构体对应的字段
	return fl
}

// 价差是否要拆分文件
func (f *FileLogger) checkSplit(file *os.File) bool {
	fileInfo, _ := file.Stat()
	fileSize := fileInfo.Size()  // 获取文件的大小
	return fileSize >= f.maxSize // 当传进来你的日志大小
}

// 封装一个切分日志的方法备份文件 新建文件
func (f *FileLogger) splitLogFile(file *os.File) *os.File {

	// 把原来的文件关闭
	fileName := file.Name() // 拿到文件的完成整路径
	backUpName := fmt.Sprintf("%s_%v.back", fileName, time.Now().Unix())
	file.Close() // 关闭当前打开的文件
	// 备份原来的文件
	os.Rename(fileName, backUpName) // 重命名
	// 新建文件
	fileObj, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0664)
	if err != nil {
		panic(fmt.Errorf("打开日志文件失败"))
	}
	return fileObj // 重新复制给文件句柄

}

// 将公用的记录日志的功能封装成一个方法
func (f *FileLogger) log(level Level, format string, args ...interface{}) {
	if f.Level > level { //
		return
	}
	msg := fmt.Sprintf(format, args...) //得到用户要记录的日志
	// 日志格式： [时间] [文件:行号] [函数名] [日志级别] 日志信息
	nowStr := time.Now().Format("2006-01-02 15:04:05.000")
	fileName, funcName, line := getCallerInfo(3) // 获取文件名 函数名 行号
	logLevelStr := getLevelStr(level)
	logMsg := fmt.Sprintf("[%s] [%s:%d] [%s] [%s] %s",
		nowStr, fileName, line, funcName, logLevelStr, msg)
	// 网文文件里面写之前要做一个检查
	// 检查单签文件是否超过了maxSize
	if f.checkSplit(f.file){
		f.file = f.splitLogFile(f.file)
	}

	fmt.Fprintf(f.file, logMsg) // 利用fmt包将msg子服装写入f.file文件中

	// 如果是error或者是fatal级别的日志还要记录到 f.errFile中
	if level >= ErrorLevel {
		if f.checkSplit(f.errFile) {
			f.errFile = f.splitLogFile(f.errFile)
		}
		fmt.Fprintln(f.errFile, logMsg)
	}
}

// Debug debug方法
func (f *FileLogger) Debug(format string, args ...interface{}) {
	f.log(DebugLevel, format, args...)
}

// Info info级别日志
func (f *FileLogger) Info(format string, args ...interface{}) {
	f.log(InfoLevel, format, args...)
}

// Warning warning级别日志
func (f *FileLogger) Warning(format string, args ...interface{}) {
	f.log(WarningLevel, format, args...)
}

// Error warning级别日志
func (f *FileLogger) Error(format string, args ...interface{}) {
	f.log(ErrorLevel, format, args...)
}

// Fatal fatal级别日志
func (f *FileLogger) Fatal(format string, args ...interface{}) {
	f.log(FatalLevel, format, args...)
}
// Close 关闭文件
func (f *FileLogger) Close() {
	f.file.Close()
	f.errFile.Close()
}

